from collisionServer import collisionServer
from cube import Cube
from vec2 import Vec2
from vec3 import Vec3
import math

class CCube(Cube):
    
    def __init__(self):
        Cube.__init__(self)
        
        collisionServer.register(self)
        self.setVar("base", "cCube")
        self.setVar("lastScale", Vec3(1000000, 1000000, 1000000))
        self.setVar("lastRot", 1000000)
        self.setVar("lastPos", Vec2(1000000, 1000000))
        self.setVar("cActive", False)
        self.setVar("vulnerable", False)
        self.changeThresh = 0.0001
        
        self.stableMass = 1000000
        self.setVar("sides",['s','s','s','s'])
        self.setVar("mass", self.stableMass)
        self.setVar("friction", 0.025)
        self.setVar("elasticity", 0)
        
    def destroy(self):
        Cube.destroy(self)
        collisionServer.unregister(self)
        
    def updateCollisionInformation(self):
        update = False
        if(self.checkSize()):
            self.cResize()
            update = True
        if(self.checkRotation()):
            self.cRotate()
            update = True
        if(self.checkPosition()):
            self.cMove()
            update = True
        return update
    
    def checkSize(self):
        s = self.getVar("scale")
        l = self.getVar("lastScale")
        v = False
        
        if( abs(s.x - l.x) > self.changeThresh ):
            v = True
        elif( abs(s.y - l.y) > self.changeThresh ):
            v = True
        elif( abs(s.z - l.z) > self.changeThresh ):
            v = True
        return v
    
    def cResize(self):
        s = self.getVar("scale")
        l = self.getVar("lastScale")
        l.x = s.x
        l.y = s.y
        l.z = s.z
        self.calcRadius()
        
    def checkRotation(self):
        r = self.getVar("rot")
        l = self.getVar("lastRot")
        v = False
        
        if( abs(r - l) > self.changeThresh ):
            v = True
        return v
        
    def cRotate(self):
        self.setVar("lastRot", self.getVar("rot"))
        self.calcNormals()
    
    def checkPosition(self):
        p = self.getVar("pos")
        l = self.getVar("lastPos")
        v = False
        
        if( abs(p.x - l.x) > self.changeThresh ):
            v = True
        elif( abs(p.y - l.y) > self.changeThresh ):
            v = True
        return v
        
    def cMove(self):
        p = self.getVar("pos")
        l = self.getVar("lastPos")
        l.x = p.x
        l.y = p.y
        self.calcMinMax()
    
    def calcNormals(self):
        if(self.hasVar("rot")):
            r = self.getVar("rot")
        
            v = Vec2()
            v.x = math.cos(r)
            v.y = math.sin(r)
            self.setVar("xNorm", v)
            
            v = Vec2()
            v.x = math.cos(r+(math.pi/2.0))
            v.y = math.sin(r+(math.pi/2.0))
            self.setVar("yNorm", v)
    
    def calcRadius(self):
        if(self.hasVar("rot")):
            v = self.getVar("scale")
            r = ((v.x/2.0)**2 + (v.y/2.0)**2)**0.5
            
            self.setVar("rad", r)
        
    def calcMinMax(self):
        if(self.hasVar("pos") and self.hasVar("rad")):
            p = self.getVar("pos")
            r = self.getVar("rad")
        
            self.setVar("xMax", p.x + r)
            self.setVar("yMax", p.y + r)
            self.setVar("xMin", p.x - r)
            self.setVar("yMin", p.y - r)
    
    def getProjectedRadius(self, box, normal):
        val = 0
        if(box.hasVar("xNorm") and box.hasVar("yNorm") and box.hasVar("scale")):
            r = box.getVar("rot")
            s = box.getVar("scale")
            
            if( (r < self.changeThresh) and ((normal.x < self.changeThresh) or (normal.y < self.changeThresh)) ):
                val = (abs(s.x * normal.x) + abs(s.y * normal.y)) / 2.0
            else:
                xN = box.getVar("xNorm")
                yN = box.getVar("yNorm")
                s  = box.getVar("scale")
                
                d1 = abs((normal.x * xN.x) + (normal.y * xN.y))
                s1 = s.x * d1
                
                d2 = abs((normal.x * yN.x) + (normal.y * yN.y))
                s2 = s.y * d2
                
                val = (s1 + s2) / 2.0
        return val
    
    def axisSeparation(self, box, normal):
        val = 0
        if(self.hasVar("pos") and box.hasVar("pos")):
            p1 = self.getVar("pos")
            p2 = box.getVar("pos")
            
            vx = p1.x - p2.x
            vy = p1.y - p2.y
            r = abs((vx * normal.x) + (vy * normal.y))
            
            val = (self.getProjectedRadius(self, normal) + self.getProjectedRadius(box, normal)) - r
        return val
        
    def collisionSide(self, box1, box2, mV):
        d1 = mV.dot(box2.getVar("xNorm"))
        d2 = mV.dot(box2.getVar("yNorm"))
        if(abs(d1) > abs(d2)):
            if(d1 > 0):
                s1 = 2
                s2 = 0
            else:
                s1 = 0
                s2 = 2
        else:
            if(d2 > 0):
                s1 = 3
                s2 = 1
            else:
                s1 = 1
                s2 = 3
        return s1, s2
    
    def checkCollision(self, obb):
        collision = True
        mD        = 1000000
        mV        = None
        minV1     = None
        minV2     = None
        side1     = -1
        side2     = -1
        
        if(self.hasVar("xNorm") and self.hasVar("yNorm") and obb.hasVar("xNorm") and obb.hasVar("yNorm")):
            for i in range(4):
                if(collision == True):
                    if(i == 0):
                        vec = self.getVar("xNorm")
                    elif(i == 1):
                        vec = self.getVar("yNorm")
                    elif(i == 2):
                        vec = obb.getVar("xNorm")
                    elif(i == 3):
                        vec = obb.getVar("yNorm")
                        
                    v = self.axisSeparation(obb, vec)
                    if(v < 0):
                        collision = False
                    else:
                        if(v < mD):
                            mD = v
                            mV = vec
                            
            if(collision == True):
                p1 = self.getVar("pos")
                p2 = obb.getVar("pos")
                dv = Vec2(p1.x-p2.x, p1.y-p2.y).norm()
                d  = dv.dot(mV)
                if(d > 0):
                    minV1 = Vec2(-mV.x, -mV.y)
                    minV2 = Vec2(mV.x, mV.y)
                else:
                    minV1 = Vec2(mV.x, mV.y)
                    minV2 = Vec2(-mV.x, -mV.y)
                side1, side2 = self.collisionSide(self, obb, minV1)
        return collision, mD, mD, minV1, minV2, side1, side2